package com.xxl.job.admin.controller;

import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.cron.CronExpression;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.core.util.JacksonUtil;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.*;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.util.XxlJobRemotingUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by xuxueli on 17/5/10.
 */
@Controller
@RequestMapping("/api")
public class JobApiController {

    @Resource
    private AdminBiz adminBiz;
    @Resource
    private XxlJobService xxlJobService;


    // ---------------------- base ----------------------

    /**
     * valid access token
     */
    private void validAccessToken(HttpServletRequest request) {
        if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null
                && XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0
                && !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_RPC_ACCESS_TOKEN))) {
            throw new XxlJobException("The access token is wrong.");
        }
    }

    /**
     * parse Param
     */
    private Object parseParam(String data, Class<?> parametrized, Class<?>... parameterClasses) {
        Object param = null;
        try {
            if (parameterClasses != null) {
                param = JacksonUtil.readValue(data, parametrized, parameterClasses);
            } else {
                param = JacksonUtil.readValue(data, parametrized);
            }
        } catch (Exception e) {
        }
        if (param == null) {
            throw new XxlJobException("The request data invalid.");
        }
        return param;
    }

    // ---------------------- admin biz ----------------------

    /**
     * callback
     *
     * @param data
     * @return
     */
    @RequestMapping("/callback")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> callback(HttpServletRequest request, @RequestBody(required = false) String data) {
        // valid
        validAccessToken(request);

        // param
        List<HandleCallbackParam> callbackParamList = (List<HandleCallbackParam>) parseParam(data, List.class, HandleCallbackParam.class);

        // invoke
        return adminBiz.callback(callbackParamList);
    }


    /**
     * registry
     *
     * @param data
     * @return
     */
    @RequestMapping("/registry")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> registry(HttpServletRequest request, @RequestBody(required = false) String data) {
        // valid
        validAccessToken(request);

        // param
        RegistryParam registryParam = (RegistryParam) parseParam(data, RegistryParam.class);

        // invoke
        return adminBiz.registry(registryParam);
    }

    /**
     * registry remove
     *
     * @param data
     * @return
     */
    @RequestMapping("/registryRemove")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> registryRemove(HttpServletRequest request, @RequestBody(required = false) String data) {
        // valid
        validAccessToken(request);

        // param
        RegistryParam registryParam = (RegistryParam) parseParam(data, RegistryParam.class);

        // invoke
        return adminBiz.registryRemove(registryParam);
    }

    // ---------------------- job biz ----------------------

    /**
     * 添加任务
     *
     * @param info 参数
     * @return 结果
     */
    @RequestMapping("/add")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> add(@RequestBody ParamInfo info) {

        XxlJobInfo target = new XxlJobInfo();
        BeanUtils.copyProperties(info, target);

        return xxlJobService.add(target);
    }

    /**
     * 添加多个任务
     *
     * @param infos 参数
     * @return 结果
     */
    @RequestMapping("/add/batch")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> addBatch(@RequestBody List<ParamInfo> infos) {


        return xxlJobService.add(infos);
    }

    @RequestMapping("/update")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> update(@RequestBody ParamInfo paramInfo) {
        XxlJobInfo target = new XxlJobInfo();
        BeanUtils.copyProperties(paramInfo, target);
        return xxlJobService.update(target);
    }


    @RequestMapping("/update/list")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> update(@RequestBody List<ParamInfo> paramInfo) {
        XxlJobInfo target = new XxlJobInfo();
        return xxlJobService.update(paramInfo);
    }

    @RequestMapping("/remove")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> remove(@RequestBody TaskInfo info) {
        return xxlJobService.remove(info.getGroupId(), info.getHandler());
    }

    @RequestMapping("/stop")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> pause(@RequestBody TaskInfo info) {

        return xxlJobService.stop(info.getGroupId(), info.getHandler());
    }

    @RequestMapping("/start")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> start(@RequestBody TaskInfo info) {

        return xxlJobService.start(info.getGroupId(), info.getHandler());
    }

    @RequestMapping("/start/list")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> start(@RequestBody List<TaskInfo> info) {

        return xxlJobService.start(info);
    }

    @RequestMapping("/create/start")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> startTask(@RequestBody ParamInfo info) {
        XxlJobInfo target = new XxlJobInfo();
        BeanUtils.copyProperties(info, target);
        ReturnT<String> returnT = xxlJobService.add(target);
        if (returnT.getCode() == 200) {
            return xxlJobService.start(Integer.valueOf(returnT.getContent()));
        }
        return returnT;
    }

    @RequestMapping("/create/start/batch")
    @ResponseBody
    @PermissionLimit(limit = false)
    public ReturnT<String> startTask(@RequestBody List<ParamInfo> info) {
        for (ParamInfo paramInfo : info) {
            XxlJobInfo target = new XxlJobInfo();
            BeanUtils.copyProperties(paramInfo, target);
            ReturnT<String> returnT = xxlJobService.add(target);
            if (returnT.getCode() == 500) {
                return returnT;
            }
            ReturnT<String> start = xxlJobService.start(Integer.valueOf(returnT.getContent()));
            if (start.getCode() == 500) {
                return returnT;
            }
        }
        return ReturnT.SUCCESS;
    }
}
